﻿namespace NetFx.SMIL.Definitions
{
  using System;
  using System.Text;
  using System.Collections;
  using System.Collections.Generic;

  using System.Reflection;
  using System.Reflection.Emit;
  using System.Runtime.InteropServices;

  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;
  using System.Security;
  using System.Security.Permissions;

  using NetFx.MSIL;
  using NetFx.SMIL.References;

  public class ParameterDef : ReflectDef
  {
    #region Statics
    public static ParameterDef of(ParameterInfo parameterInfo)
    {
      return new ParameterDef(parameterInfo);
    }
    public static ParameterDef of(string name)
    {
      return new ParameterDef(name);
    }
    #endregion
    #region Fields
    protected TypeRef parameterType;
    protected ParameterAttributes attributes = ParameterAttributes.None;
    protected int index = 0;
    protected object defaultValue = null;
    protected MemberRef member = null;
    protected int metadataToken = 0;
    protected List<TypeRef> optionalCustomModifiers = null;
    protected List<TypeRef> requiredCustomModifiers = null;
    #endregion
    #region Properties
    public override DefType DefinitionType
    {
      get { return DefType.Parameter; }
    }
    public virtual TypeRef ParameterType
    {
      get
      {
        return this.parameterType;
      }
      set
      {
        this.parameterType = value;
      }
    }
    public virtual ParameterAttributes Attributes
    {
      get
      {
        return this.attributes;
      }
      set
      {
        this.attributes = value;
      }
    }
    public virtual int Index
    {
      get
      {
        return this.index;
      }
      set
      {
        this.index = value;
      }
    }
    public virtual object DefaultValue
    {
      get
      {
        return this.defaultValue;
      }
      set
      {
        this.defaultValue = value;
      }
    }
    public virtual MemberRef Member
    {
      get
      {
        return this.member;
      }
    }
    public virtual int MetadataToken
    {
      get
      {
        return this.metadataToken;
      }
    }
    public virtual List<TypeRef> OptionalCustomModifiers
    {
      get
      {
        return this.optionalCustomModifiers == null
          ? this.optionalCustomModifiers = new List<TypeRef>()
          : this.optionalCustomModifiers;
      }
    }
    public virtual List<TypeRef> RequiredCustomModifiers
    {
      get
      {
        return this.requiredCustomModifiers == null
          ? this.requiredCustomModifiers = new List<TypeRef>()
          : this.requiredCustomModifiers;
      }
    }    
    public virtual bool IsIn
    {
      get
      {
        return ((this.attributes & ParameterAttributes.In) != ParameterAttributes.None);
      }
      set
      {
          if (value)
        {
          this.attributes |= ParameterAttributes.In;
        }
        else
        {
          this.attributes &= (~ParameterAttributes.In);
        }     
      }
    }
    public virtual bool IsOut
    {
      get
      {
        return ((this.attributes & ParameterAttributes.Out) != ParameterAttributes.None);
      }
      set
      {
          if (value)
        {
          this.attributes |= ParameterAttributes.Out;
        }
        else
        {
          this.attributes &= (~ParameterAttributes.Out);
        }     
      }
    }
    public virtual bool IsLcid
    {
      get
      {
        return ((this.attributes & ParameterAttributes.Lcid) != ParameterAttributes.None);
      }
    set
    {
      if (value)
      {
        this.attributes |= ParameterAttributes.Lcid;
      }
      else
      {
        this.attributes &= (~ParameterAttributes.Lcid);
      }   
    }
    }
    public virtual bool IsOptional
    {
      get
      {
        return ((this.attributes & ParameterAttributes.Optional) != ParameterAttributes.None);
      }
      set
      {
         if (value)
        {
          this.attributes |= ParameterAttributes.Optional;
        }
        else
        {
          this.attributes &= (~ParameterAttributes.Optional);
        }   
      }
    }
    public virtual bool IsRetval
    {
      get
      {
         return ((this.attributes & ParameterAttributes.Retval) != ParameterAttributes.None);
      }
      set
      {
         if (value)
        {
          this.attributes |= ParameterAttributes.Retval;
        }
        else
        {
          this.attributes &= (~ParameterAttributes.Retval);
        }
      }
    }
    #endregion
    #region Constructors
    public ParameterDef(string name):base(name)
    {

    }
    public ParameterDef(string name, Type parameterType)
      : this(name)
    {
      this.parameterType =TypeRef.of(parameterType);
    }
    public ParameterDef(string name, Type parameterType, ParameterAttributes attributes)
      : this(name, parameterType)
    {
      this.attributes = attributes;
    }
    public ParameterDef(string name, Type parameterType, ParameterAttributes attributes,int index)
      : this(name, parameterType,attributes)
    {
      this.index = index;
    }
    public ParameterDef(ParameterInfo parameterInfo)
      :base(String.Empty)
    {
      this.OnReflecting(parameterInfo);
    }
    #endregion
    #region Methods
    #region Publics
    public virtual TypeRef AddOptionalType(TypeRef type)
    {
      if (type != null)
      {
        this.OptionalCustomModifiers.Add(type);
      }
      return type;
    }
    public virtual TypeRef RemoveOptionalType(TypeRef type)
    {
      if (type != null)
      {
        this.OptionalCustomModifiers.Remove(type);
      }
      return type;
    }
    public virtual TypeRef AddRequiredType(TypeRef type)
    {
      if (type != null)
      {
        this.RequiredCustomModifiers.Add(type);
      }
      return type;
    }
    public virtual TypeRef RemoveRequiredType(TypeRef type)
    {
      if (type != null)
      {
        this.RequiredCustomModifiers.Remove(type);
      }
      return type;
    }
    #endregion
    #region Internals
    protected override AnyGenerator OnCompleting(AnyGenerator generator)
    {
      if (generator is ParameterGenerator)
      {
        ((ParameterGenerator)generator).DefaultValue = this.DefaultValue;
      }
      return base.OnCompleting(generator);
    }
    protected override AnyGenerator OnDefining(AnyGenerator container)
    {
      if (container is MethodGenerator)
      {
        return ((MethodGenerator)container).DefineParameter(this.Name,this.ParameterType.ReflectInfo,this.Attributes,this.Index);
      }
      return base.OnDefining(container);
    }
    protected override ReflectDef  OnReflecting(object source)
    {
      if (source is ParameterInfo)
      {
        ParameterInfo pi = source as ParameterInfo;
        this.attributes = pi.Attributes;
        this.parameterType =TypeRef.of(pi.ParameterType);
        this.index = pi.Position;
        //TODO: FIX IT
        //this.member = MemberRef.of(pi.Member);
        this.defaultValue = pi.DefaultValue;
        this.metadataToken = pi.MetadataToken;

        this.ReloadMembers(pi.GetOptionalCustomModifiers(), this.OptionalCustomModifiers);
        this.ReloadMembers(pi.GetRequiredCustomModifiers(), this.RequiredCustomModifiers);
      }
      return base.OnReflecting(source);
    }

    protected override void DisposeList(bool disposing)
    {
      if (disposing)
      {
        this.DisposeList(this.OptionalCustomModifiers);
        this.DisposeList(this.RequiredCustomModifiers);
      }
    }
    protected override void OnBreakingReference()
    {
      this.Break(this.ParameterType);
      this.Break(this.Member);
      this.Break(this.OptionalCustomModifiers);
      this.Break(this.RequiredCustomModifiers);
      base.OnBreakingReference();
    }
    #endregion
    #endregion
  }
}